Android逆向之smali
点击蓝字 · 关注我们
前言
Smali是Android虚拟机的反汇编语言。在安卓逆向中是非常重要的,就类似于汇编语言。本篇文章给大家带来关于Smali的基本语法和远程动态调试。在接触的时候,如果有JVM字节码基础,会发现两者还是有相似的地方。
这里推荐一个AS的插件,java2smali,可以将java代码转换为smali,可以让人更好的实践理解smali.
JAVA的类型与smali描述
java 类型 smail 描述符
boolean Z
byte B
short S
char C
int I
long J
float F
double D
void V
数组 L
对象 [../../
返回关键字
smali方法返回关键字和其后面可以跟的数据类型
return byte
return short
return int
return char
return boolean
return float
return-wide double
return-wide long
return-void void
return-object 数组
return-object object
异常指令
throw
数据转换指令
int-to-long 整型转为长整型
float-to-int 单精度浮点型转为整型
int-tobyte 整型转为字节类型
neg-int 求补指令,对整数求补
not-int 求反指令,对整数求反
比较指令
cmpl-类型 VC,VA,VB,比较VA,VB较小值
cmpg-类型 VC,VA,VB 比较VA,VB较大值
数据定义指令
const-string 字符串值
const-class 字节码对象赋值
const/4 最大存放4位数值(-8到7)
const/16 最大存放16位数值(-32768到32767)
const 最大存放32位数值
const/high16 只存放高16位数值
const-wide 最大存放64位数值
const-wide/16 最大存放16位数值
const-wide/32 最大存放32位数值
const-wide/high16 只存放高16位数值
变量操作指令
move v1,v2
将v2中的值移入到v1寄存器中(4位,支持int型)
move/from16 v1,v2
将16位的v2寄存器中的值移入到8位的v1寄存器这
move/16 v1,v2
将16位的v2寄存器中的值移入到16位的v1寄存器中
move-wide v1,v2
将16位的v2寄存器中的值移入到v1寄存器对中
move-wide/from16 v1,v2
将16位的v2寄存器(一组)中的值移入到8位的v1寄存器在中
move-wide/16 v1,v2
将16位的v2寄存器(一组)中的值移入到16位的v1寄存器中
move-object v1,v2
将v2中的对象指针移入到v1寄存器中
move-object v1,v2
将v2中的对象指针移入到v1寄存器中
move-object/from16 v1,v2
将16位的v2寄存器中的对象指针移入到v1(8位)寄存器中
move-object/16 v1,v2
将16位的v2寄存器中的对象指针移入到v1(16位)寄存器中
move-result v1
将这个指令的上一条指令计算结果,移入到v1寄存器中(需要配合invoke-staic、invoke-virtual等指令使用)
move-result-object v1
将上条计算结果的对象指针移入v1寄存器
move-result-wide
v1将上条计算结果(双字)的对象指针移入v1寄存器
move-exception
v1 将异常移入v1寄存器,用于捕获try-catch语句中的异常
条件跳转指令
if-eq vA,vB,:cond_ 如果vA等于vB,则跳转
if-ne vA,vB, :cond_ 如果vA不等于vB,则跳转
if-lt vA,vB, :cond_ 如果vA小于vB,则跳转
if-le vA,vB, :cond_ 如果vA小于等于vB,则跳转
if-gt vA,vB, :cond_ 如果vA大于vB,则跳转
if-ge vA,vB, :cond_ 如果vA大于等于vb,则跳转
if-eqz vA,:cond_ 如果vA等于0,则跳转
if-nez vA,:cond_ 如果vA不等于0,在跳转
if-ltz vA,:cond_ 如果vA小于0,则跳转
if-lez vA,:cond_ 如果vA小于等于0,则跳转
if-gtz vA,:cond_ 如果vA大于0,则跳转
if-gez vA,:cond_ 如果vA大于等于0,则跳转
Smali关键词
.class 包名+类名
.super 父类类名
.source 源文件名称
.implements 接口实现
.field 定义变量
.method/.end method 方法的开始与结束
.locals 方法内使用的v开头的寄存器个数
.prologue 表示方法中代码的开始处
.line 对于java中的行数
.paramter/.param 指定的方法参数
.annotation./end annotation 注解的开始和结束
.registers 表示该方法使用到的寄存器的个数
.local 表示方法中非参数的变量
.cond_N 条件分支,配合if使用
.goto_N goto跳转标记
寄存器
v变量表示方法中非参数变量
p变量表示方法中参数变量
方法调用指令
invoke-direct 调用私有方法和构造方法
invoke-virtual 调用普通的实例方法,(被public,protected或没有修饰符的方法)
invoke-static 调用静态方法
invoke-super 调用父类方法
invoke-interface 调用接口中的方法
利用插件实操
这里我们用java2smali这个插件进行实际操作。
从这里可以我们可以得到它是com/example/first/包中的,继承的父类是androidx/appcompat/app/AppCompatActivity,名字是MainActivity.java
从这里我们可以看出这一段是变量定义,可以从中得出它的变量名,访问修饰符,类型。
这里看到这是一段init方法,可以看出它用到的寄存器个数,调用的方法和返回值的类型。
Smali远程调试
这里用到的工具:
夜神模拟器
adb
smalidea
monitor.exe
夜神模拟器和adb就不说了,主要讲一下smalidea和monitor.exe还有调试步骤。
smalidea,这里之前直接用的网上教程0.05版本的,但是用了之后报错,所以换成了0.06的,这里踩了一个坑。
monitor.exe是自带的,但是使用的时候要注意系统架构的适配。
这里一般存放的路径是在SDK里的tools下的lib.会发现有两个文件夹,选一个适合自己机子的。
接下来用的案例是教我兄弟学android逆向的文件。
这里输入下面这个命令
adb shell am start -D -n hfdcxy.com.myapplication/hfdcxy.com.myapplication.MainActivity
可以看到monitor已经监控到了
这里需要注意到3111这个(每次都会不一样),下面的命令需要用到。
这里再用adb forward tcp:8700 jdwp:3111,
3111这一部分,则需要根据情况修改。在用这个命令的适合要先关掉monitor,不然会报错。
这里再把从网上下载到的smalidea插件放到plugins目录下。然后File->settings->plugins,然后再点击如下图的地方。
这里还要再修改Editor->File Types。移掉smali support的*.smali.把smalidea中添加*.smali.
接下来把smali导入到AS中。
再配置一下JDK
现在就可以开始愉快的debug了。